#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h> 



//确定主设备号
static int major  = 0;
static struct class *gpio_drv_class;
static struct gpio_desc *gpio_drv_des;

static int gpio;

/* 3. 实现对应的open/read/write等函数，填入file_operations结构体                   */
static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

/* write(fd, &val, 1); */
static ssize_t gpio_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	char status;
	
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(&status, buf, 1);

	/* 根据次设备号和status控制LED */
	// gpiod_set_value(gpio_drv_des, status);
	gpio_direction_output(gpio,status);
	return 1;
}

static int gpio_drv_open (struct inode *node, struct file *file)
{
	//int minor = iminor(node);
	
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	/* 根据次设备号初始化LED */
	gpiod_direction_output(gpio_drv_des, 0);
	
	return 0;
}

static int gpio_drv_close (struct inode *node, struct file *file)
{
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static struct file_operations gpio_drv = {
	.owner	 = THIS_MODULE,
	.open    = gpio_drv_open,
	.read    = gpio_drv_read,
	.write   = gpio_drv_write,
	.release = gpio_drv_close,
};


//从设备树 中的 节点中获取资源    获得 gpio_drv 中的数据
//将file_operation 结构体提交到内核 注册驱动程序
static int gpio_drv_probe(struct platform_device *pdev)
{

	enum of_gpio_flags flag; 
	struct device_node *rk_led_node = pdev->dev.of_node;
	const char* dedefault_state ;

    printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	gpio = of_get_named_gpio_flags(rk_led_node, "gpios", 0, &flag);
	of_property_read_string(rk_led_node,"dedefault-state",&dedefault_state);//从设备树中获取指定的  字符串
	/* >0 有效   ； <0 无效 */
	if (!gpio_is_valid(gpio))
	{	
		printk(KERN_INFO "gpio 无效\n");
		return -ENODEV;
	}
	printk(KERN_INFO "gpio num is %d  of_gpio_flags  = %d  dedefault_state = %s\n", gpio,flag,dedefault_state);
	gpio_direction_output(gpio,flag);	//设置默认输出
	/* 申请GPIO */
	gpio_request(gpio, "gpios");

    // //从设备树中获取gpio
    // gpio_drv_des = gpiod_get(&pdev->dev,"gpio",0);
    // if(IS_ERR(gpio_drv_des))  //检查是否获取成
    // {
    //     dev_err(&pdev->dev,"error not get gpio pin\n");
    //     return PTR_ERR(gpio_drv_des);
    // }   

    //注册file_operation 结构体
    major = register_chrdev(major,"my_gpio_drv",&gpio_drv);

	//创建  gpio_drv 类
	gpio_drv_class = class_create(THIS_MODULE,"my_gpio_class");
	//判断是创建成功 
	if(IS_ERR(gpio_drv_class))
	{
		 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		 unregister_chrdev(major,"my_gpio_drv");
		 gpiod_put(gpio_drv_des);//释放gpio
		 return PTR_ERR(gpio_drv_class);
	}

	device_create(gpio_drv_class,NULL,MKDEV(major, 0),NULL,"my_gpio_drv%d",0);//创建设备
	return  0;

}

static int gpio_drv_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(gpio_drv_class, MKDEV(major, 0));
	class_destroy(gpio_drv_class);
	unregister_chrdev(major, "my_gpio_drv");
	gpio_free(gpio);
    
    return 0;
}



static struct of_device_id gpios[] = 
{
    {.compatible = "gpio_drv"},
    {},
};

//定义 platform_driver
static  struct platform_driver gpio_drv_platform_driver =
{
    .probe = gpio_drv_probe,
    .remove = gpio_drv_remove,
    .driver =
    {
        .name = "gpio_drv",
        .of_match_table = gpios,
    },

};


//注册平台设备
static int __init gpio_drv_init(void)
{
	int err;
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = platform_driver_register(&gpio_drv_platform_driver);
	return  err;
}

//卸载平台设备 ， 在设备卸载的时候调用
static void gpio_drv_exit(void)
{
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	platform_driver_unregister(&gpio_drv_platform_driver);
}


//使用内核宏 将设备告诉内核
module_init(gpio_drv_init);
module_exit(gpio_drv_exit);
MODULE_LICENSE("GPL");
